home *** CD-ROM | disk | FTP | other *** search
/ Aminet 41 / Aminet 41 (2001)(Schatztruhe)[!][Feb 2001].iso / Aminet / dev / c / libmpeg_src.lha / extras / ParseArgv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-22  |  11.9 KB  |  420 lines

  1. /*
  2.  * ParseArgv.c --
  3.  *
  4.  *    This file contains a procedure that handles table-based
  5.  *    argv-argc parsing.
  6.  *
  7.  * Copyright 1990 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  *
  16.  *
  17.  * This file has been modified to not rely on tcl, tk or X11.
  18.  * Based on tkArgv.c from tk2.3 : 
  19. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkArgv.c,v 1.12 92/08/07 08:39:48 ouster Exp $ SPRITE (Berkeley)";
  20.  *
  21.  * Modifications by Peter Neelin (November 27, 1992)
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include "ParseArgv.h"
  28.  
  29. #define TRUE  1
  30. #define FALSE 0
  31.  
  32. /*
  33.  * Default table of argument descriptors.  These are normally available
  34.  * in every application.
  35.  */
  36.  
  37. static ArgvInfo defaultTable[] = {
  38.     {"-help",    ARGV_HELP,    (char *) NULL,    (char *) NULL,
  39.     "Print summary of command-line options and abort"},
  40.     {NULL,    ARGV_END,    (char *) NULL,    (char *) NULL,
  41.     (char *) NULL}
  42. };
  43.  
  44. /*
  45.  * Forward declarations for procedures defined in this file:
  46.  */
  47.  
  48. static void    PrintUsage _ANSI_ARGS_((ArgvInfo *argTable, int flags));
  49.  
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * ParseArgv --
  54.  *
  55.  *    Process an argv array according to a table of expected
  56.  *    command-line options.  See the manual page for more details.
  57.  *
  58.  * Results:
  59.  *    The return value is a Boolean value with TRUE indicating an error.  
  60.  *    If an error occurs then an error message is printed on stderr.
  61.  *    Under normal conditions, both *argcPtr and *argv are modified
  62.  *    to return the arguments that couldn't be processed here (they
  63.  *    didn't match the option table, or followed an ARGV_REST
  64.  *    argument).
  65.  *
  66.  * Side effects:
  67.  *
  68.  *----------------------------------------------------------------------
  69.  */
  70.  
  71. int
  72. ParseArgv(argcPtr, argv, argTable, flags)
  73.     int *argcPtr;        /* Number of arguments in argv.  Modified
  74.                  * to hold # args left in argv at end. */
  75.     char **argv;        /* Array of arguments.  Modified to hold
  76.                  * those that couldn't be processed here. */
  77.     ArgvInfo *argTable;    /* Array of option descriptions */
  78.     int flags;            /* Or'ed combination of various flag bits,
  79.                  * such as ARGV_NO_DEFAULTS. */
  80. {
  81.    register ArgvInfo *infoPtr;
  82.                 /* Pointer to the current entry in the
  83.                  * table of argument descriptions. */
  84.    ArgvInfo *matchPtr;    /* Descriptor that matches current argument. */
  85.    char *curArg;        /* Current argument */
  86.    register char c;        /* Second character of current arg (used for
  87.                  * quick check for matching;  use 2nd char.
  88.                  * because first char. will almost always
  89.                  * be '-'). */
  90.    int srcIndex;        /* Location from which to read next argument
  91.                  * from argv. */
  92.    int dstIndex;        /* Index into argv to which next unused
  93.                  * argument should be copied (never greater
  94.                  * than srcIndex). */
  95.    int argc;            /* # arguments in argv still to process. */
  96.    int length;            /* Number of characters in current argument. */
  97.    int nargs;        /* Number of following arguments to get. */
  98.    int i;
  99.  
  100. /* Macro to optionally print errors */
  101. #define FPRINTF if (!(flags&ARGV_NO_PRINT)) fprintf
  102.  
  103.    if (flags & ARGV_DONT_SKIP_FIRST_ARG) {
  104.       srcIndex = dstIndex = 0;
  105.       argc = *argcPtr;
  106.    } else {
  107.       srcIndex = dstIndex = 1;
  108.       argc = *argcPtr-1;
  109.    }
  110.  
  111.    while (argc > 0) {
  112.       curArg = argv[srcIndex];
  113.       srcIndex++;
  114.       argc--;
  115.       c = curArg[1];
  116.       length = strlen(curArg);
  117.       
  118.       /*
  119.        * Loop throught the argument descriptors searching for one with
  120.        * the matching key string.  If found, leave a pointer to it in
  121.        * matchPtr.
  122.        */
  123.  
  124.       matchPtr = NULL;
  125.       for (i = 0; i < 2; i++) {
  126.          if (i == 0) {
  127.             infoPtr = argTable;
  128.          } else {
  129.             infoPtr = defaultTable;
  130.          }
  131.          for (; infoPtr->type != ARGV_END; infoPtr++) {
  132.             if (infoPtr->key == NULL) {
  133.                continue;
  134.             }
  135.             if ((infoPtr->key[1] != c)
  136.                 || (strncmp(infoPtr->key, curArg, length) != 0)) {
  137.                continue;
  138.             }
  139.             if (infoPtr->key[length] == 0) {
  140.                matchPtr = infoPtr;
  141.                goto gotMatch;
  142.             }
  143.             if (flags & ARGV_NO_ABBREV) {
  144.                continue;
  145.             }
  146.             if (matchPtr != NULL) {
  147.                FPRINTF(stderr, "ambiguous option \"%s\"\n", curArg);
  148.                return TRUE;
  149.             }
  150.             matchPtr = infoPtr;
  151.          }
  152.       }
  153.       if (matchPtr == NULL) {
  154.  
  155.          /*
  156.           * Unrecognized argument.  Just copy it down, unless the caller
  157.           * prefers an error to be registered.
  158.           */
  159.  
  160.          if (flags & ARGV_NO_LEFTOVERS) {
  161.             FPRINTF(stderr, "unrecognized argument \"%s\"\n", curArg);
  162.          }
  163.          argv[dstIndex] = curArg;
  164.          dstIndex++;
  165.          continue;
  166.       }
  167.  
  168.       /*
  169.        * Take the appropriate action based on the option type
  170.        */
  171.     gotMatch:
  172.       infoPtr = matchPtr;
  173.       switch (infoPtr->type) {
  174.       case ARGV_CONSTANT:
  175.          *((int *) infoPtr->dst) = (int) infoPtr->src;
  176.          break;
  177.       case ARGV_INT:
  178.          nargs = (int) infoPtr->src;
  179.          if (nargs<1) nargs=1;
  180.          for (i=0; i<nargs; i++) {
  181.             if (argc == 0) {
  182.                goto missingArg;
  183.             } else {
  184.                char *endPtr;
  185.  
  186.                *(((int *) infoPtr->dst)+i) =
  187.                   strtol(argv[srcIndex], &endPtr, 0);
  188.                if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
  189.                   FPRINTF(stderr, 
  190.                   "expected integer argument for \"%s\" but got \"%s\"",
  191.                           argv[srcIndex]);
  192.                   return TRUE;
  193.                }
  194.                srcIndex++;
  195.                argc--;
  196.             }
  197.          }
  198.          break;
  199.       case ARGV_STRING:
  200.          nargs = (int) infoPtr->src;
  201.          if (nargs<1) nargs=1;
  202.          for (i=0; i<nargs; i++) {
  203.             if (argc == 0) {
  204.                goto missingArg;
  205.             } else {
  206.                *(((char **)infoPtr->dst)+i) = argv[srcIndex];
  207.                srcIndex++;
  208.                argc--;
  209.             }
  210.          }
  211.          break;
  212.       case ARGV_REST:
  213.          *((int *) infoPtr->dst) = dstIndex;
  214.          goto argsDone;
  215.       case ARGV_FLOAT:
  216.          nargs = (int) infoPtr->src;
  217.          if (nargs<1) nargs=1;
  218.          for (i=0; i<nargs; i++) {
  219.             if (argc == 0) {
  220.                goto missingArg;
  221.             } else {
  222.                char *endPtr;
  223.  
  224.                *(((double *) infoPtr->dst)+i) =
  225.                   strtod(argv[srcIndex], &endPtr);
  226.                if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
  227.                   FPRINTF(stderr, 
  228.        "expected floating-point argument for \"%s\" but got\"%s\"\n",
  229.                           infoPtr->key, argv[srcIndex]);
  230.                   return TRUE;
  231.                }
  232.                srcIndex++;
  233.                argc--;
  234.             }
  235.          }
  236.          break;
  237.       case ARGV_FUNC: {
  238.          int (*handlerProc)();
  239.  
  240.          handlerProc = (int (*)())infoPtr->src;
  241.         
  242.          if ((*handlerProc)(infoPtr->dst, infoPtr->key,
  243.                             argv[srcIndex])) {
  244.             srcIndex += 1;
  245.             argc -= 1;
  246.          }
  247.          break;
  248.       }
  249.       case ARGV_GENFUNC: {
  250.          int        (*handlerProc)();
  251.  
  252.          handlerProc = (int (*)())infoPtr->src;
  253.  
  254.          argc = (*handlerProc)(infoPtr->dst, infoPtr->key,
  255.                                argc, argv+srcIndex);
  256.          if (argc < 0) {
  257.             return TRUE;
  258.          }
  259.          break;
  260.       }
  261.       case ARGV_HELP:
  262.          PrintUsage (argTable, flags);
  263.          return TRUE;
  264.       default:
  265.          FPRINTF(stderr, "bad argument type %d in ArgvInfo",
  266.                  infoPtr->type);
  267.          return TRUE;
  268.       }
  269.    }
  270.    
  271.    /*
  272.     * If we broke out of the loop because of an OPT_REST argument,
  273.     * copy the remaining arguments down.
  274.     */
  275.  
  276.  argsDone:
  277.    while (argc) {
  278.       argv[dstIndex] = argv[srcIndex];
  279.       srcIndex++;
  280.       dstIndex++;
  281.       argc--;
  282.    }
  283.    argv[dstIndex] = (char *) NULL;
  284.    *argcPtr = dstIndex;
  285.    return FALSE;
  286.  
  287.  missingArg:
  288.    FPRINTF(stderr, "\"%s\" option requires an additional argument\n", curArg);
  289.    return TRUE;
  290. }
  291.  
  292. /*
  293.  *----------------------------------------------------------------------
  294.  *
  295.  * PrintUsage --
  296.  *
  297.  *    Generate a help string describing command-line options.
  298.  *
  299.  * Results:
  300.  *    Prints on stderr (unless ARGV_NO_PRINT is specified in flags) 
  301.  *    a help string describing all the options in argTable, plus all those
  302.  *    in the default table unless ARGV_NO_DEFAULTS is
  303.  *    specified in flags.
  304.  *
  305.  * Side effects:
  306.  *    None.
  307.  *
  308.  *----------------------------------------------------------------------
  309.  */
  310.  
  311. static void
  312. PrintUsage(argTable, flags)
  313.      ArgvInfo *argTable;    /* Array of command-specific argument
  314.                  * descriptions. */
  315.      int flags;            /* If the ARGV_NO_DEFAULTS bit is set
  316.                  * in this word, then don't generate
  317.                  * information for default options. */
  318. {
  319.    register ArgvInfo *infoPtr;
  320.    int width, i, j, numSpaces;
  321. #define NUM_SPACES 20
  322.    static char spaces[] = "                    ";
  323.    char tmp[30];
  324.    int nargs;
  325.  
  326. /* Macro to optionally print errors */
  327. #define FPRINTF if (!(flags&ARGV_NO_PRINT)) fprintf
  328.  
  329.    /*
  330.     * First, compute the width of the widest option key, so that we
  331.     * can make everything line up.
  332.     */
  333.  
  334.    width = 4;
  335.    for (i = 0; i < 2; i++) {
  336.       for (infoPtr = i ? defaultTable : argTable;
  337.            infoPtr->type != ARGV_END; infoPtr++) {
  338.          int length;
  339.          if (infoPtr->key == NULL) {
  340.             continue;
  341.          }
  342.          length = strlen(infoPtr->key);
  343.          if (length > width) {
  344.             width = length;
  345.          }
  346.       }
  347.    }
  348.  
  349.    FPRINTF(stderr, "Command-specific options:");
  350.    for (i = 0; ; i++) {
  351.       for (infoPtr = i ? defaultTable : argTable;
  352.            infoPtr->type != ARGV_END; infoPtr++) {
  353.          if ((infoPtr->type == ARGV_HELP) && (infoPtr->key == NULL)) {
  354.             FPRINTF(stderr, "\n%s", infoPtr->help);
  355.             continue;
  356.          }
  357.          FPRINTF(stderr, "\n %s:", infoPtr->key);
  358.          numSpaces = width + 1 - strlen(infoPtr->key);
  359.          while (numSpaces > 0) {
  360.             if (numSpaces >= NUM_SPACES) {
  361.                FPRINTF(stderr, "%s",spaces);
  362.             } else {
  363.                FPRINTF(stderr, "%s",spaces+NUM_SPACES-numSpaces);
  364.             }
  365.             numSpaces -= NUM_SPACES;
  366.          }
  367.          FPRINTF(stderr, "%s",infoPtr->help);
  368.          switch (infoPtr->type) {
  369.          case ARGV_INT: {
  370.             FPRINTF(stderr, "\n\t\tDefault value:");
  371.             nargs = (int) infoPtr->src;
  372.             if (nargs<1) nargs=1;
  373.             for (j=0; j<nargs; j++) {
  374.                FPRINTF(stderr, " %d", *(((int *) infoPtr->dst)+j));
  375.             }
  376.             break;
  377.          }
  378.          case ARGV_FLOAT: {
  379.             FPRINTF(stderr, "\n\t\tDefault value:");
  380.             nargs = (int) infoPtr->src;
  381.             if (nargs<1) nargs=1;
  382.             for (j=0; j<nargs; j++) {
  383.                FPRINTF(stderr, " %lg", *(((double *) infoPtr->dst)+j));
  384.             }
  385.             break;
  386.          }
  387.          case ARGV_STRING: {
  388.             char *string;
  389.  
  390.             nargs = (int) infoPtr->src;
  391.             if (nargs<1) nargs=1;
  392.             string = *((char **) infoPtr->dst);
  393.             if ((nargs==1) && (string == NULL)) break;
  394.             for (j=0; j<nargs; j++) {
  395.                string = *(((char **) infoPtr->dst)+j);
  396.                if (string != NULL) {
  397.                   FPRINTF(stderr, " \"%s\"", string);
  398.                }
  399.                else {
  400.                   FPRINTF(stderr, " \"\"", string);
  401.                }
  402.             }
  403.  
  404.             break;
  405.          }
  406.          default: {
  407.             break;
  408.          }
  409.          }
  410.       }
  411.  
  412.       if ((flags & ARGV_NO_DEFAULTS) || (i > 0)) {
  413.          break;
  414.       }
  415.       FPRINTF(stderr, "\nGeneric options for all commands:");
  416.    }
  417.  
  418.    FPRINTF(stderr, "\n");
  419. }
  420.